home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Tool Chest / Development Tools & Languages / Dylan Related / Mindy-1.1 (sources only) / mindy-1.1 / interp / thread.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-18  |  17.4 KB  |  789 lines  |  [TEXT/ttxt]

  1. /**********************************************************************\
  2. *
  3. *  Copyright (c) 1994  Carnegie Mellon University
  4. *  All rights reserved.
  5. *  
  6. *  Use and copying of this software and preparation of derivative
  7. *  works based on this software are permitted, including commercial
  8. *  use, provided that the following conditions are observed:
  9. *  
  10. *  1. This copyright notice must be retained in full on any copies
  11. *     and on appropriate parts of any derivative works.
  12. *  2. Documentation (paper or online) accompanying any system that
  13. *     incorporates this software, or any part of it, must acknowledge
  14. *     the contribution of the Gwydion Project at Carnegie Mellon
  15. *     University.
  16. *  
  17. *  This software is made available "as is".  Neither the authors nor
  18. *  Carnegie Mellon University make any warranty about the software,
  19. *  its performance, or its conformity to any specification.
  20. *  
  21. *  Bug reports, questions, comments, and suggestions should be sent by
  22. *  E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  23. *
  24. ***********************************************************************
  25. *
  26. * $Header: thread.c,v 1.20 94/07/26 18:34:10 hallgren Exp $
  27. *
  28. * This file implements threads, and the various synchronization
  29. * primitives.
  30. *
  31. \**********************************************************************/
  32.  
  33. #include <string.h>
  34. #ifdef sparc
  35. #include <memory.h>
  36. #endif
  37.  
  38. #include "mindy.h"
  39. #include "gc.h"
  40. #include "bool.h"
  41. #include "class.h"
  42. #include "thread.h"
  43. #include "obj.h"
  44. #include "driver.h"
  45. #include "func.h"
  46. #include "num.h"
  47. #include "list.h"
  48. #include "def.h"
  49. #include "type.h"
  50. #include "error.h"
  51.  
  52. #define STACK_SIZE (1*1024*1024)
  53.  
  54. static struct thread_list *AllThreads = NULL;
  55. static struct thread_list **AllThreadsTail = &AllThreads;
  56. static int NextId = 0;
  57.  
  58. static struct thread *Current = NULL;
  59. static struct thread *Runnable = NULL;
  60.  
  61. static obj_t obj_ThreadClass, obj_LockClass, obj_SpinLockClass, obj_EventClass;
  62.  
  63. static void remove_from_lock(struct thread *thread);
  64. static void add_to_lock(struct thread *thread);
  65. static void remove_from_event(struct thread *thread);
  66.  
  67.  
  68.  
  69. struct thread_list *all_threads(void)
  70. {
  71.     return AllThreads;
  72. }
  73.  
  74.  
  75.  
  76. /* Scheduling stuff. */
  77.  
  78. struct thread *thread_current()
  79. {
  80.     return Current;
  81. }
  82.  
  83. static obj_t dylan_current_thread()
  84. {
  85.     return Current->thread_obj;
  86. }
  87.  
  88. void thread_set_current(struct thread *thread)
  89. {
  90.     Current = thread;
  91. }
  92.  
  93. struct thread *thread_pick_next()
  94. {
  95.     struct thread *thread = Runnable;
  96.  
  97.     if (thread)
  98.     Runnable = thread->next;
  99.  
  100.     Current = thread;
  101.  
  102.     return thread;
  103. }
  104.  
  105.  
  106. /* Utilities. */
  107.  
  108. static void set_status(struct thread *thread, enum thread_status status)
  109. {
  110.     thread->status = status;
  111.     THREAD(thread->thread_obj)->status = status;
  112. }
  113.  
  114. static void suspend_thread(struct thread *thread)
  115. {
  116.     if (thread == Runnable) {
  117.     if (thread == thread->next)
  118.         Runnable = NULL;
  119.     else {
  120.         Runnable = thread->next;
  121.         *thread->prev = Runnable;
  122.         Runnable->prev = thread->prev;
  123.     }
  124.     }
  125.     else {
  126.     *thread->prev = thread->next;
  127.     thread->next->prev = thread->prev;
  128.     }
  129.  
  130.     thread->next = NULL;
  131.     thread->prev = NULL;
  132. }
  133.  
  134. static void wakeup_thread(struct thread *thread)
  135. {
  136.     if (thread->suspend_count == 0) {
  137.     if (Runnable) {
  138.         thread->next = Runnable;
  139.         thread->prev = Runnable->prev;
  140.         *thread->prev = thread;
  141.         Runnable->prev = &thread->next;
  142.     }
  143.     else {
  144.         thread->next = thread;
  145.         thread->prev = &thread->next;
  146.         Runnable = thread;
  147.     }
  148.     set_status(thread, status_Running);
  149.     }
  150.     else
  151.     set_status(thread, status_Suspended);
  152. }
  153.  
  154. static void return_false(struct thread *thread)
  155. {
  156.     obj_t *old_sp = pop_linkage(thread);
  157.  
  158.     *old_sp = obj_False;
  159.     thread->sp = old_sp + 1;
  160.  
  161.     do_return(thread, old_sp, old_sp);
  162. #if SLOW_LONGJMP
  163.     go_on();
  164. #endif
  165. }
  166.  
  167. static void stop_thread(struct thread *thread, obj_t *vals)
  168. {
  169.     obj_t thread_obj = thread->thread_obj;
  170.  
  171.     assert(Current == thread);
  172.  
  173.     thread_kill(thread);
  174.  
  175.     THREAD(thread_obj)->status = status_Exited;
  176.  
  177.     pause(pause_PickNewThread);
  178. }
  179.  
  180. static void start_thread(struct thread *thread)
  181. {
  182.     obj_t *old_sp = obj_rawptr(thread->datum);
  183.  
  184.     thread->advance = NULL;
  185.     thread->datum = obj_False;
  186.  
  187.     invoke(thread, (thread->sp - old_sp) - 1);
  188. }
  189.  
  190.  
  191. /* Thread creation. */
  192.  
  193. struct thread *thread_create(obj_t debug_name)
  194. {
  195.     obj_t thread_obj = alloc(obj_ThreadClass, sizeof(struct thread_obj));
  196.     struct thread_list *list = malloc(sizeof(*list));
  197.     struct thread *thread = malloc(STACK_SIZE);
  198.  
  199.     THREAD(thread_obj)->thread = thread;
  200.     THREAD(thread_obj)->debug_name = debug_name;
  201.  
  202.     list->thread = thread;
  203.     list->next = NULL;
  204.     *AllThreadsTail = list;
  205.     AllThreadsTail = &list->next;
  206.  
  207.     thread->thread_obj = thread_obj;
  208.     thread->id = NextId++;
  209.     thread->next = NULL;
  210.     thread->prev = NULL;
  211.     thread->suspend_count = 1;
  212.     thread->advance = start_thread;
  213.     set_status(thread, status_Suspended);
  214.     thread->datum = rawptr_obj(thread+1);
  215.     thread->stack_base = (obj_t *)(thread+1);
  216.     thread->stack_end = (obj_t *)(((void *)thread) + STACK_SIZE);
  217.     thread->sp = thread->stack_base;
  218.     thread->fp = NULL;
  219.     thread->component = 0;
  220.     thread->pc = 0;
  221.     thread->cur_catch = obj_False;
  222.     thread->cur_uwp = NULL;
  223.     thread->handlers = obj_False;
  224.  
  225.     set_c_continuation(thread, stop_thread);
  226.  
  227.     return thread;
  228. }
  229.  
  230. static obj_t dylan_spawn_thread(obj_t debug_name, obj_t func)
  231. {
  232.     struct thread *thread = thread_create(debug_name);
  233.  
  234.     *thread->sp++ = func;
  235.  
  236.     thread_restart(thread);
  237.  
  238.     return thread->thread_obj;
  239. }
  240.  
  241.  
  242.  
  243. /* Pushing escape frames. */
  244.  
  245. static void pop_escape_frame(struct thread *thread, obj_t *vals)
  246. {
  247.     thread->sp = vals;
  248.     thread_pop_escape(thread);
  249. }
  250.  
  251. void thread_push_escape(struct thread *thread)
  252. {
  253.     switch (thread->status) {
  254.       case status_Running:
  255.     suspend_thread(thread);
  256.     break;
  257.  
  258.       case status_Suspended:
  259.     *thread->sp++ = make_fixnum(thread->suspend_count);
  260.     break;
  261.  
  262.       case status_Debuggered:
  263.     break;
  264.  
  265.       case status_Blocked:
  266.     remove_from_lock(thread);
  267.     break;
  268.  
  269.       case status_Waiting:
  270.     remove_from_event(thread);
  271.     break;
  272.  
  273.       default:
  274.     lose("strange thread status.");
  275.     }
  276.  
  277.     *thread->sp++ = thread->datum;
  278.     *thread->sp++ = make_fixnum((int)thread->status);
  279.     *thread->sp++ = rawptr_obj(thread->advance);
  280.     *thread->sp++ = thread->component;
  281.     *thread->sp++ = make_fixnum(thread->pc);
  282.  
  283.     thread->advance = start_thread;
  284.     set_status(thread, status_Suspended);
  285.     thread->suspend_count = 1;
  286.     thread->datum = rawptr_obj(thread->sp);
  287.     set_c_continuation(thread, pop_escape_frame);
  288. }
  289.  
  290. void thread_pop_escape(struct thread *thread)
  291. {
  292.     thread->pc = fixnum_value(*--thread->sp);
  293.     thread->component = *--thread->sp;
  294.     thread->advance = obj_rawptr(*--thread->sp);
  295.     set_status(thread, (enum thread_status)fixnum_value(*--thread->sp));
  296.     thread->datum = *--thread->sp;
  297.     
  298.     switch (thread->status) {
  299.       case status_Running:
  300.     break;
  301.  
  302.       case status_Suspended:
  303.     suspend_thread(thread);
  304.     thread->suspend_count = fixnum_value(*--thread->sp);
  305.     break;
  306.  
  307.       case status_Debuggered:
  308.     suspend_thread(thread);
  309.     break;
  310.  
  311.       case status_Blocked:
  312.     add_to_lock(thread);
  313.     break;
  314.  
  315.       case status_Waiting:
  316.     set_status(thread, status_Running);
  317.     break;
  318.  
  319.       default:
  320.     lose("strange thread status.");
  321.     }
  322. }
  323.  
  324.  
  325. /* Thread destruction */
  326.  
  327. void thread_kill(struct thread *thread)
  328. {
  329.     struct thread_list *list, **prev;
  330.  
  331.     switch (thread->status) {
  332.       case status_Running:
  333.     suspend_thread(thread);
  334.     break;
  335.       case status_Suspended:
  336.       case status_Debuggered:
  337.     break;
  338.       case status_Blocked:
  339.     remove_from_lock(thread);
  340.     break;
  341.       case status_Waiting:
  342.     remove_from_event(thread);
  343.     break;
  344.  
  345.       default:
  346.     lose("strange thread status.");
  347.     }
  348.  
  349.     for (prev = &AllThreads; (list = *prev) != NULL; prev = &list->next) {
  350.     if (list->thread == thread) {
  351.         struct thread_list *next = list->next;
  352.         *prev = next;
  353.         if (next == NULL)
  354.         AllThreadsTail = prev;
  355.         free(list);
  356.         break;
  357.     }
  358.     }
  359.     assert(list != NULL);
  360.  
  361.     if (Current == thread)
  362.     Current = NULL;
  363.  
  364.     THREAD(thread->thread_obj)->thread = NULL;
  365.     THREAD(thread->thread_obj)->status = status_Killed;
  366.  
  367.     free(thread);
  368. }
  369.  
  370. static obj_t dylan_kill_thread(obj_t thread_obj)
  371. {
  372.     struct thread *thread = THREAD(thread_obj)->thread;
  373.     boolean me = (thread == Current);
  374.  
  375.     thread_kill(thread);
  376.  
  377.     if (me)
  378.     pause(pause_PickNewThread);
  379.  
  380.     return thread_obj;
  381. }
  382.     
  383.  
  384.  
  385. /* Thread suspending and restarting. */
  386.  
  387. void thread_debuggered(struct thread *thread, obj_t condition)
  388. {
  389.     assert(thread == Current);
  390.  
  391.     suspend_thread(thread);
  392.     set_status(thread, status_Debuggered);
  393.     thread->datum = condition;
  394.     pause(pause_DebuggerInvoked);
  395. }
  396.  
  397. void thread_buggered(struct thread *thread)
  398. {
  399.     if (thread->status != status_Debuggered)
  400.     lose("Trying to bugger a thread that wasn't originally Debuggered?");
  401.     else {
  402.     wakeup_thread(thread);
  403.     set_status(thread, status_Running);
  404.     thread->datum = obj_False;
  405.     }
  406. }
  407.  
  408. void thread_suspend(struct thread *thread)
  409. {
  410.     if (thread->suspend_count++ == 0 && thread->status == status_Running) {
  411.     suspend_thread(thread);
  412.     set_status(thread, status_Suspended);
  413.     }
  414. }
  415.  
  416. void thread_restart(struct thread *thread)
  417. {
  418.     if (thread->suspend_count > 0) {
  419.     thread->suspend_count--;
  420.     if (thread->suspend_count == 0 && thread->status == status_Suspended)
  421.         wakeup_thread(thread);
  422.     }
  423. }
  424.  
  425.  
  426.  
  427. /* Locks */
  428.  
  429. struct lock {
  430.     obj_t class;
  431.     boolean locked;
  432.     struct thread *waiting;
  433.     struct thread **last;
  434. };
  435.  
  436. #define LOCK(o) obj_ptr(struct lock *, o)
  437.  
  438. obj_t make_lock(void)
  439. {
  440.     obj_t res = alloc(obj_SpinLockClass, sizeof(struct lock));
  441.  
  442.     LOCK(res)->locked = FALSE;
  443.     LOCK(res)->waiting = NULL;
  444.     LOCK(res)->last = &LOCK(res)->waiting;
  445.  
  446.     return res;
  447. }
  448.  
  449. boolean lock_query(obj_t lock)
  450. {
  451.     return LOCK(lock)->locked;
  452. }
  453.  
  454. static obj_t dylan_lock_query(obj_t lock)
  455. {
  456.     if (lock_query(lock))
  457.     return obj_True;
  458.     else
  459.     return obj_False;
  460. }
  461.  
  462. void lock_grab(struct thread *thread, obj_t lock,
  463.            void advance(struct thread *thread))
  464. {
  465.     if (LOCK(lock)->locked) {
  466.     suspend_thread(thread);
  467.     *LOCK(lock)->last = thread;
  468.     LOCK(lock)->last = &thread->next;
  469.     thread->next = NULL;
  470.     thread->prev = NULL;
  471.     set_status(thread, status_Blocked);
  472.     thread->datum = lock;
  473.     thread->advance = advance;
  474.  
  475.     pause(pause_PickNewThread);
  476.     }
  477.     else {
  478.     LOCK(lock)->locked = TRUE;
  479.     advance(thread);
  480.     }
  481. }
  482.  
  483. static obj_t dylan_lock_grab(obj_t lock)
  484. {
  485.     lock_grab(Current, lock, return_false);
  486.     /* lock_grab doesn't return. */
  487.     lose("lock_grab actually returned?");
  488.     return NULL;
  489. }
  490.  
  491. void lock_release(obj_t lock)
  492. {
  493.     struct thread *waiting = LOCK(lock)->waiting;
  494.  
  495.     if (waiting != NULL) {
  496.     struct thread *next = waiting->next;
  497.  
  498.     LOCK(lock)->waiting = next;
  499.     if (next == NULL)
  500.         LOCK(lock)->last = &LOCK(lock)->waiting;
  501.     wakeup_thread(waiting);
  502.     waiting->datum = obj_False;
  503.     }
  504.     else
  505.     LOCK(lock)->locked = FALSE;
  506. }
  507.  
  508. static obj_t dylan_lock_release(obj_t lock)
  509. {
  510.     if (!LOCK(lock)->locked)
  511.     error("%= is already unlocked.", lock);
  512.  
  513.     lock_release(lock);
  514.  
  515.     return obj_False;
  516. }
  517.  
  518. static void remove_from_lock(struct thread *thread)
  519. {
  520.     obj_t lock = thread->datum;
  521.     struct thread *scan, **prev;
  522.  
  523.     prev = &LOCK(lock)->waiting;
  524.     while (1) {
  525.     scan = *prev;
  526.     if (scan == NULL)
  527.         lose("Tried to remove a thread from an lock it "
  528.          "wasn't waiting on.");
  529.     if (scan == thread) {
  530.         *prev = thread->next;
  531.         if (thread->next == NULL)
  532.         LOCK(lock)->last = prev;
  533.         return;
  534.     }
  535.     }
  536. }
  537.  
  538. static void add_to_lock(struct thread *thread)
  539. {
  540.     obj_t lock = thread->datum;
  541.  
  542.     if (LOCK(lock)->locked) {
  543.     suspend_thread(thread);
  544.     *LOCK(lock)->last = thread;
  545.     LOCK(lock)->last = &thread->next;
  546.     thread->next = NULL;
  547.     thread->prev = NULL;
  548.     }
  549.     else {
  550.     LOCK(lock)->locked = TRUE;
  551.     thread->datum = obj_False;
  552.     }
  553. }
  554.  
  555.  
  556. /* Events. */
  557.  
  558. struct event {
  559.     obj_t class;
  560.     struct thread *waiting;
  561.     struct thread **last;
  562. };
  563.  
  564. #define EVENT(o) obj_ptr(struct event *, o)
  565.  
  566. obj_t make_event(void)
  567. {
  568.     obj_t res = alloc(obj_EventClass, sizeof(struct event));
  569.     
  570.     EVENT(res)->waiting = NULL;
  571.     EVENT(res)->last = &EVENT(res)->waiting;
  572.  
  573.     return res;
  574. }
  575.  
  576. void event_wait(struct thread *thread, obj_t event, obj_t lock,
  577.         void (*advance)(struct thread *thread))
  578. {
  579.     if (lock != obj_False && !LOCK(lock)->locked)
  580.     error("%= is already unlocked.", lock);
  581.  
  582.     suspend_thread(thread);
  583.     *EVENT(event)->last = thread;
  584.     EVENT(event)->last = &thread->next;
  585.     thread->prev = NULL;
  586.     thread->next = NULL;
  587.     set_status(thread, status_Waiting);
  588.     thread->datum = event;
  589.     thread->advance = advance;
  590.  
  591.     if (lock != obj_False)
  592.     lock_release(lock);
  593.  
  594.     pause(pause_PickNewThread);
  595. }    
  596.  
  597. static obj_t dylan_event_wait(obj_t event, obj_t lock)
  598. {
  599.     event_wait(Current, event, lock, return_false);
  600.     /* event_wait doesn't return. */
  601.     lose("event_wait actually returned?\n");
  602.     return NULL;
  603. }
  604.  
  605. obj_t event_signal(obj_t event)
  606. {
  607.     struct thread *waiting;
  608.  
  609.     waiting = EVENT(event)->waiting;
  610.  
  611.     if (waiting != NULL) {
  612.     struct thread *next = waiting->next;
  613.  
  614.     EVENT(event)->waiting = next;
  615.     if (next == NULL)
  616.         EVENT(event)->last = &EVENT(event)->waiting;
  617.     wakeup_thread(waiting);
  618.     waiting->datum = obj_False;
  619.     }
  620.  
  621.     return obj_False;
  622. }
  623.  
  624. obj_t event_broadcast(obj_t event)
  625. {
  626.     struct thread *waiting;
  627.     
  628.     waiting = EVENT(event)->waiting;
  629.  
  630.     while (waiting != NULL) {
  631.     struct thread *next = waiting->next;
  632.  
  633.     wakeup_thread(waiting);
  634.     waiting->datum = obj_False;
  635.  
  636.     waiting = next;
  637.     }
  638.     EVENT(event)->waiting = NULL;
  639.     EVENT(event)->last = &EVENT(event)->waiting;
  640.  
  641.     return obj_False;
  642. }
  643.  
  644. static void remove_from_event(struct thread *thread)
  645. {
  646.     obj_t event = thread->datum;
  647.     struct thread *scan, **prev;
  648.  
  649.     prev = &EVENT(event)->waiting;
  650.     while (1) {
  651.     scan = *prev;
  652.     if (scan == NULL)
  653.         lose("Tried to remove a thread from an event it "
  654.          "wasn't waiting on.");
  655.     if (scan == thread) {
  656.         *prev = thread->next;
  657.         if (thread->next == NULL)
  658.         EVENT(event)->last = prev;
  659.         thread->datum = obj_False;
  660.         return;
  661.     }
  662.     }
  663. }
  664.  
  665.  
  666. /* GC stuff. */
  667.  
  668. static int scav_thread_obj(struct object *o)
  669. {
  670.     struct thread_obj *t = (struct thread_obj *)o;
  671.  
  672.     scavenge(&t->debug_name);
  673.  
  674.     return sizeof(struct thread_obj);
  675. }
  676.  
  677. static obj_t trans_thread_obj(obj_t t)
  678. {
  679.     return transport(t, sizeof(struct thread_obj));
  680. }
  681.  
  682. static int scav_lock(struct object *o)
  683. {
  684.     struct lock *lock = (struct lock *)o;
  685.  
  686.     if (lock->waiting == NULL)
  687.     lock->last = &lock->waiting;
  688.  
  689.     return sizeof(struct lock);
  690. }
  691.  
  692. static obj_t trans_lock(obj_t lock)
  693. {
  694.     return transport(lock, sizeof(struct lock));
  695. }
  696.  
  697. static int scav_event(struct object *o)
  698. {
  699.     struct event *event = (struct event *)o;
  700.  
  701.     if (event->waiting == NULL)
  702.     event->last = &event->waiting;
  703.  
  704.     return sizeof(struct event);
  705. }
  706.  
  707. static obj_t trans_event(obj_t event)
  708. {
  709.     return transport(event, sizeof(struct event));
  710. }
  711.  
  712. static void scav_thread(struct thread *thread)
  713. {
  714.     obj_t *ptr;
  715.  
  716.     scavenge(&thread->thread_obj);
  717.     scavenge(&thread->datum);
  718.     scavenge(&thread->component);
  719.     scavenge(&thread->cur_catch);
  720.     scavenge(&thread->handlers);
  721.  
  722.     for (ptr = thread->stack_base; ptr < thread->sp; ptr++)
  723.     scavenge(ptr);
  724.     memset(thread->sp, 0, (thread->stack_end - thread->sp) * sizeof(obj_t));
  725. }
  726.  
  727. void scavenge_thread_roots(void)
  728. {
  729.     struct thread_list *list;
  730.  
  731.     for (list = AllThreads; list != NULL; list = list->next)
  732.     scav_thread(list->thread);
  733.  
  734.     scavenge(&obj_ThreadClass);
  735.     scavenge(&obj_LockClass);
  736.     scavenge(&obj_SpinLockClass);
  737.     scavenge(&obj_EventClass);
  738. }
  739.  
  740.  
  741. /* Init stuff. */
  742.  
  743. void make_thread_classes(void)
  744. {
  745.     obj_ThreadClass = make_builtin_class(scav_thread_obj, trans_thread_obj);
  746.     obj_LockClass = make_abstract_class(FALSE);
  747.     obj_SpinLockClass = make_builtin_class(scav_lock, trans_lock);
  748.     obj_EventClass = make_builtin_class(scav_event, trans_event);
  749. }
  750.  
  751. void init_thread_classes(void)
  752. {
  753.     init_builtin_class(obj_ThreadClass, "<thread>", obj_ObjectClass, NULL);
  754.     init_builtin_class(obj_LockClass, "<lock>", obj_ObjectClass, NULL);
  755.     init_builtin_class(obj_SpinLockClass, "<spinlock>", obj_LockClass, NULL);
  756.     init_builtin_class(obj_EventClass, "<event>", obj_ObjectClass, NULL);
  757. }
  758.  
  759. void init_thread_functions(void)
  760. {
  761.     define_function("spawn-thread", list2(obj_ObjectClass, obj_FunctionClass),
  762.             FALSE, obj_False, FALSE, obj_ThreadClass,
  763.             dylan_spawn_thread);
  764.     define_function("current-thread", obj_Nil, FALSE, obj_False, FALSE,
  765.             obj_ThreadClass, dylan_current_thread);
  766.     define_function("kill-thread", list1(obj_ThreadClass), FALSE, obj_False,
  767.             FALSE, obj_ThreadClass, dylan_kill_thread);
  768.  
  769.     define_method("make", list1(singleton(obj_LockClass)), FALSE, obj_Nil,
  770.           FALSE, obj_SpinLockClass, make_lock);
  771.     define_method("make", list1(singleton(obj_SpinLockClass)), FALSE, obj_Nil,
  772.           FALSE, obj_SpinLockClass, make_lock);
  773.     define_method("locked?", list1(obj_SpinLockClass), FALSE, obj_False,
  774.           FALSE, obj_BooleanClass, dylan_lock_query);
  775.     define_method("grab-lock", list1(obj_SpinLockClass), FALSE, obj_False,
  776.           FALSE, obj_ObjectClass, dylan_lock_grab);
  777.     define_method("release-lock", list1(obj_SpinLockClass), FALSE, obj_False,
  778.           FALSE, obj_ObjectClass, dylan_lock_release);
  779.  
  780.     define_method("make", list1(singleton(obj_EventClass)), FALSE, obj_Nil,
  781.           FALSE, obj_EventClass, make_event);
  782.     define_method("wait-for-event", list2(obj_EventClass, obj_SpinLockClass),
  783.           FALSE, obj_False, FALSE, obj_ObjectClass, dylan_event_wait);
  784.     define_method("signal-event", list1(obj_EventClass),
  785.           FALSE, obj_False, FALSE, obj_ObjectClass, event_signal);
  786.     define_method("broadcast-event", list1(obj_EventClass),
  787.           FALSE, obj_False, FALSE, obj_ObjectClass, event_broadcast);
  788. }
  789.